﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Amba.System.Extensions;
using Amba.ULogin.Models;
using Newtonsoft.Json.Linq;
using Orchard;
using Orchard.ContentManagement;
using Orchard.Core.Common.Fields;
using Orchard.Core.Common.Models;
using Orchard.Data;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.Roles.Models;
using Orchard.Roles.Services;
using Orchard.Security;
using Orchard.Users.Models;

using Orchard.Users.Models;

namespace Amba.ULogin.Services
{

    public interface IULoginService : IDependency
    {
        UserPart GetUserBySocial(ULoginUser uLoginUser);
        UserPart CreateUser(ULoginUser uLoginUser);
        bool Logon(UserPart user, bool rememberMe);
        void UpdateUserFieds(UserPart user, ULoginUser uLoginUser);
        Dictionary<string, string> ConverToPropertiesDictionary(UserPart user);

        void AddUserToRoles(int userId, IEnumerable<string> roleNames);
    }

    public class ULoginService : IULoginService
    {
        private readonly IOrchardServices _orchardServices;
        private readonly IMembershipService _membershipService;
        private readonly IAuthenticationService _authenticationService;
        private readonly IRepository<ULoginUserRecord> _logMeInUserRepository;
        private readonly IContentManager _contentManager;
        private readonly IRoleService _roleService;
        private readonly IRepository<UserRolesPartRecord> _userRolesRepository;
        private readonly IUserToolsService _userToolsService;
        private readonly IULoginServiceSettings _serviceSettings;

        public ULoginService(
            IAuthenticationService authenticationService, 
            IMembershipService membershipService, 
            IOrchardServices orchardServices, 
            IRepository<ULoginUserRecord> logMeInUserRepository, IContentManager contentManager, 
            IRoleService roleService, IRepository<UserRolesPartRecord> userRolesRepository,
            IUserToolsService userToolsService,
            IULoginServiceSettings serviceSettings)
        {
            _authenticationService = authenticationService;
            _membershipService = membershipService;
            _orchardServices = orchardServices;
            _logMeInUserRepository = logMeInUserRepository;
            _contentManager = contentManager;
            _roleService = roleService;           
            _userRolesRepository = userRolesRepository;
            _userToolsService = userToolsService;
            _serviceSettings = serviceSettings;
        }

        public void AddUserToRoles(int userId, IEnumerable<string> roleNames)
        {
            foreach (var roleName in roleNames)
            {
                var roleRecord = _roleService.GetRoleByName(roleName);
                if (roleRecord != null)
                {
                    _userRolesRepository.Create(new UserRolesPartRecord()
                    {
                        Role = roleRecord,
                        UserId = userId
                    });
                }
            }
        }

        public UserPart GetUserBySocial(ULoginUser uLoginUser)
        {
            var record = 
                _logMeInUserRepository.Table.Where(x => x.Network == uLoginUser.Network && x.SocialKey == uLoginUser.Uid).OrderByDescending(x => x.UserId).FirstOrDefault();
            
            if (record == null)
                return null;
            return _orchardServices.ContentManager.Get<UserPart>(record.UserId);
        }

        public UserPart CreateUser(ULoginUser uLoginUser)
        {
            var userName = GenerateUserName(uLoginUser);

            var user = _membershipService.CreateUser(
                new CreateUserParams(userName, Guid.NewGuid().ToString(), uLoginUser.Email, null, null, true)) as UserPart;

            if (user == null)
            {
                return null;
            }
            UpdateUserFieds(user, uLoginUser);
            _contentManager.Publish(user.ContentItem);
            var record = new ULoginUserRecord()
            {
                Network = uLoginUser.Network,
                SocialKey = uLoginUser.Uid,
                UserId = user.Id,
                LastData = uLoginUser.ResponseData
            };
            _logMeInUserRepository.Create(record);
            _logMeInUserRepository.Flush();

            return user;
        }

        private string GenerateUserName(ULoginUser uLoginUser)
        {
            var userName = Guid.NewGuid().ToString();
            string testName;
            if (!string.IsNullOrWhiteSpace(uLoginUser.Nickname))
            {
                testName = uLoginUser.Nickname.Trim().ToLower();
                if (_membershipService.GetUser(testName) == null)
                {
                    return testName;
                }
                if (!string.IsNullOrWhiteSpace(uLoginUser.Network))
                {
                    testName += "@" + uLoginUser.Network;
                    if (_membershipService.GetUser(testName) == null)
                    {
                        return testName;
                    }
                }
            }
            if (!string.IsNullOrWhiteSpace(uLoginUser.Email))
            {
                testName = uLoginUser.Email.ToLower().Trim().RegexRemove("@.*^");
                if (uLoginUser.IsVerifiedEmail && _membershipService.GetUser(testName) == null)
                {
                    return uLoginUser.Email;
                }
            }

            testName = (uLoginUser.FirstName + "_" + uLoginUser.LastName).Replace(" ", "_").Trim().ToLower();
            if (!string.IsNullOrWhiteSpace(testName) && _membershipService.GetUser(testName) == null)
            {
                return testName;
            }
            
            return userName;
        }

        public Dictionary<string, string> ConverToPropertiesDictionary(UserPart user)
        {
            var userResult = new Dictionary<string, string>();
            userResult["UserName"] = user.UserName;
            userResult["Email"] = user.Email;
            var part = user.ContentItem.Parts.FirstOrDefault(x => x.PartDefinition.Name == "User");
            if (part != null)
            {
                IEnumerable<TextField> userFields = part.Fields.OfType<TextField>().ToList();
                foreach (var field in userFields)
                {
                    var fieldName = field.Name.ToLower().Trim();
                    switch (fieldName)
                    {
                        case "displayname":
                            userResult["DisplayName"] = field.Value;
                            break;
                        case "lastname":
                            userResult["LastName"] = field.Value;
                            break;
                        case "firstname":
                            userResult["FirstName"] = field.Value;
                            break;
                        case "photo":
                            userResult["UserPic"] = field.Value;
                            break;
                    }
                    userResult[fieldName] = field.Value;
                }
            }
            return userResult;
        }



        public void UpdateUserFieds(UserPart user, ULoginUser uLoginUser)
        {
            var part = user.ContentItem.Parts.FirstOrDefault(x => x.PartDefinition.Name == "User");

            string photo = uLoginUser.GetStringValue("photo");
            string photoBig = uLoginUser.GetStringValue("photo_big");

            if (!string.IsNullOrWhiteSpace(photo))
            {
                photo = _userToolsService.SaveUserPic(user.UserName, photo, "photo");
            }
            if (!string.IsNullOrWhiteSpace(photoBig))
            {
                photoBig = _userToolsService.SaveUserPic(user.UserName, photoBig, "photo_big");
            }


            if (part != null)
            {
                IEnumerable<TextField> userFields = part.Fields.OfType<TextField>().ToList();
                foreach (var field in userFields)
                {
                    var fieldName = field.Name.ToLower().Trim();
                    if (fieldName == "displayname")
                        field.Value = (uLoginUser.FirstName + " " + uLoginUser.LastName).Trim();
                    if (fieldName == "lastname")
                        field.Value = uLoginUser.LastName;
                    if (fieldName == "firstname")
                        field.Value = uLoginUser.FirstName;
                }
                foreach (JProperty property in uLoginUser.Properties)
                {
                    var field = userFields.FirstOrDefault(x => x.Name == property.Name.RegexRemove("_"));
                    if (field != null)
                    {
                        var value = uLoginUser.GetStringValue(property.Name).Trim();

                        if (_serviceSettings.Settings.SaveUserPhotoToDisk)
                        {
                            if (field.Name == "photo")
                            {
                                value = photo;
                            }
                            if (property.Name == "photo_big")
                            {
                                value = photoBig;
                            }
                        }
                        field.Value = value;
                    }
                }
            }
            var userDatePart = user.As<ULoginUserDataPart>();
            if (userDatePart != null)
            {
                userDatePart.Uid = uLoginUser.Uid;
                userDatePart.FirstName = uLoginUser.FirstName;
                userDatePart.LastName = uLoginUser.LastName;
                userDatePart.Nickname = uLoginUser.Nickname;
                userDatePart.ULoginResponce = uLoginUser.ResponseData;
                userDatePart.Email = uLoginUser.Email;
                userDatePart.BDate = uLoginUser.BDate;
                userDatePart.Phone = uLoginUser.Phone;
                userDatePart.UserIdentity = uLoginUser.Identity;
                userDatePart.Network = uLoginUser.Network;
                userDatePart.Sex = uLoginUser.Sex;
                userDatePart.IsVerifiedEmail = uLoginUser.IsVerifiedEmail;
                userDatePart.City = uLoginUser.City;
                userDatePart.Country = uLoginUser.Country;
                userDatePart.Photo = string.IsNullOrWhiteSpace(photo) ? uLoginUser.Photo : photo;
                userDatePart.PhotoBig = string.IsNullOrWhiteSpace(photoBig) ? uLoginUser.PhotoBig : photoBig;
                userDatePart.Profile = uLoginUser.Profile;
            }
        }

        public bool Logon(UserPart user, bool rememberMe)
        {
            if (user == null)
            {
                return false;
            }

            var currentUser = _authenticationService.GetAuthenticatedUser();
            if (currentUser != null) _authenticationService.SignOut();

            if (user.RegistrationStatus != UserStatus.Approved)
            {
                return false;
                //return new QuickLogOnResponse { User = null, Error = T("User was disabled by site administrator"), ReturnUrl = request.ReturnUrl };
            }

            _authenticationService.SignIn(user, rememberMe);
            return true;
        }
    }
}